/* 
 * Autores:
 *      Jonathan Lopez  11106
 *      Jorge Martínez  11237
 * 
 * Archivo: 
 * Última Revision: $Rev: 69 $
 *      Fecha: $Date: 2011-09-19 06:58:38 +0000 (Mon, 19 Sep 2011) $
 */ 


package Interface;
import Interface.Dialogos.*;
import Manejo.Transporte.Registros.*;
import Manejo.Transporte.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Scanner;

 /**
 * Clase de interaccion con el usuario a traves de la consola.
 * 
 * @author Jorge Martinez
 * @author Jonathan Lopez
 */  
public class ConsolaUI
{
    private RegBarcos registroBarcos;
    private RegContenedores registroContenedores;
    private RegNavieras registroNavieras;
    private RegPuertos registroPuertos;
    private RegRutas registroRutas;
    private final Registros registros;
    
    private final Dialogos dialogar;
    private final Scanner ingreso;
    

    public ConsolaUI(Registros registros)
    {
        this.registroBarcos = registros.obtenerRegistroBarcos();
        this.registroContenedores = registros.obtenerRegistroContenedores();
        this.registroNavieras = registros.obtenerRegistroNavieras();
        this.registroPuertos = registros.obtenerRegistroPuertos();
        this.registroRutas = registros.obtenerRegistroRutas();
        this.registros = registros;
        
        this.ingreso = new Scanner(System.in);
        this.dialogar = new Dialogos( this.ingreso, this.registros );
    }
    
    /**
     * Menú para el manejo del programa principal.
     */
    public void iniciarPrograma()
    {   
        limpiarPantalla();
        /*
         * Mensaje de Bienvenida
         */
        System.out.println("¡Bienvenido a NAVIPRO!\n");
        System.out.print("Este sistema le permite manejar viajes de Barcos ");
        System.out.println("a través de Navieras para llevar sus Productos ");
        System.out.println("a cualquier Puerto que se encuentre en los registros.");
        System.out.print("\nNOTA: En cualquier momento puede ingresar 'FINAL' ");
        System.out.println("para terminar el ingreso de datos.");
        
        try{
            do{
                // Realizar unos chequeos iniciales
                boolean hayBarcos =
                        registroBarcos.obtenerTodosBarcos().length>0;
                boolean hayContenedores =
                        registroContenedores.obtenerTodosContenedores().length>0;
                boolean hayNavieras =
                        registroNavieras.obtenerTodasNavieras().length>0;
                boolean hayPuertos =
                        registroPuertos.obtenerTodosPuertos().length>0;
                boolean hayRutas =
                        registroRutas.obtenerTodasRutas().length>0;
                
                
                // Si no hay navieras o Puertos
                if( !hayNavieras || !hayPuertos ){
                    if( !primeraInteraccion(hayNavieras, hayPuertos) )
                        throw new InterruptionException();
                } else {
                    System.out.println("\nEspere un momento mientras se actualizan los registros.");                    
                    System.out.println("¿Qué desea hacer?");
                    String mensaje="1. Ver registro de Puertos." +
                            "\n2. Ver registro de Navieras." +
                            "\n3. Ver registro de Barcos." +
                            "\n4. Ver registro de Rutas." +
                            "\n5. Ver Cargamentos." +
                            "\n6. Salir del programa.\nOpcion: ";
                    switch(dialogar.pedirInt(mensaje, 1, 6))
                    {
                        case 1:
                        {
                            interactuarPuertos();
                            break;
                        }
                        case 2:
                        {
                            interactuarNavieras();
                            break;
                        }
                        case 3:
                        {
                            interactuarBarcos();
                            break;
                        }
                        case 4:
                        {
                            interactuarRutas();
                            break;
                        }
                        case 5:
                        {
                            consolidarCarga();
                            break;
                        }
                        case 6:
                        {
                            System.out.println("Esperamos que vuelva pronto. Ciao");
                            return;
                        }
                    }
                }
                
                limpiarPantalla();
            }while( true );
            
        }catch(InterruptionException ex){
            System.out.println("\nEsperamos que vuelva pronto. Ciao");
            return;
        } 
    }
    
    /**
     * Método que permite la interaccion con el usuario al momento de agregar 
     * Barcos al sistema.
     */
     private void interactuarBarcos()
     {
        while(true)
        {
            limpiarPantalla();
            String mensaje="\nEscoja la opción que desea realizar."
                    + "\n1. Ver los Barcos disponibles."
                    + "\n2. Ingresar un Barco."
                    + "\n3. Asignar Ruta a un Barco."
                    + "\n4. Eliminar un Barco."
                    + "\n5. Menú anterior.\nOpcion: ";
            try {
                switch( dialogar.pedirInt(mensaje, 1, 5) )
                {
                    case 1: // Imprimir los Barcos
                    {
                        // System.out.println("Espere mientras se imprime el registro de barcos");
                        dialogar.mostrarRegistroObjeto(ObjetoRegistrable.Barcos);
                        break;
                    }
                    case 2: // Ingresar un Barco
                    {
                        ID idBarco = dialogar.pedirObjeto(ObjetoRegistrable.Barcos);
                        if( !idBarco.equals(ID.idNulo) ){
                            dialogar.mostrarPausa("\n¡Barco agregado exitosamente!");
                        }
                        break;
                    }
                    case 3: // Asignar Ruta
                    {
                        // Escoger Barco
                        System.out.println("Escoja el Barco al que desea asignar la Ruta");
                        ID idBarco = dialogar.escogerObjeto(ObjetoRegistrable.Barcos);
                        if( idBarco.equals(ID.idNulo) )
                            break;
                        Barco barcoActual = registroBarcos.obtenerBarco(idBarco);
                        
                        /* Verificar Viaje anterior */
                        Viaje viajeAnterior = barcoActual.obtenerViaje();
                        if( viajeAnterior != null && !viajeAnterior.viajeCompletado() ){
                            System.out.println("El Barco escogido no ha terminado su viaje anterior.");
                            if( !dialogar.pedirDecision("¿Esta seguro que desea continuar (S/N)? ") )
                                break;
                        }
                        
                        // Escoger Ruta
                        System.out.println("Escoja la Ruta que desea utilizar");
                        ID idRuta = dialogar.escogerObjeto(ObjetoRegistrable.Rutas);
                        if( idRuta.equals(ID.idNulo) )
                            break;
                        
                        // Ingresar Fecha
                        Date fechaInicio = dialogar.pedirFecha( "Ingrese la fecha de partida: " );
                        Viaje nuevoViaje = new Viaje(idRuta, fechaInicio, registros);
                        
                        // Confirmar Barco, Ruta y Fecha
                        if( dialogar.pedirDecision("¿Esta seguro que desea asignar la Ruta al Barco (S/N)? ") )
                            barcoActual.cambiarViaje(nuevoViaje);
                        break;
                    }
                    case 4: // Eliminar un Barco
                    {
                        System.out.println("Escoja a continuación el Barco que desea eliminar.");
                        ID idBarco = dialogar.escogerObjeto(ObjetoRegistrable.Barcos);
                        if( !idBarco.equals(ID.idNulo) )
                            if( dialogar.pedirDecision("¿Esta seguro que desea eliminar el Barco (S/N)? " ) )
                                registroBarcos.eliminarBarco(idBarco);
                        break;
                    }
                    case 5: // Regresar al menu principal
                    {
                        return;
                    }
               }
            } catch (InterruptionException ex) {
                return;
            }
       }
    }
             
   /**
     * Método que permite el manejo de Puertos con el usuario. Puede ver registros, 
     * agregar Puertos o eliminar Puertos.
     */
    private void interactuarPuertos()
    {
        while(true)
        {
            limpiarPantalla();
            String mensaje="\nEscoja la opción que desea realizar."
                    + "\n1. Ver los Puertos disponibles. "
                    + "\n2. Ingresar un Puerto."
                    + "\n3. Eliminar un Puerto."
                    + "\n4. Menú principal.\nOpcion: ";
            try {
                switch(dialogar.pedirInt(mensaje, 1, 4))
                {
                    case 1: // Ver puertos
                    {
                        //System.out.println("Espere mientras se imprime el registro de puertos");
                        dialogar.mostrarRegistroObjeto(ObjetoRegistrable.Puertos);
                        break;
                    }
                    case 2: // Agregar Puerto
                    {
                        ID idPuerto = dialogar.pedirObjeto(ObjetoRegistrable.Puertos);
                        if( !idPuerto.equals(ID.idNulo) ){
                            dialogar.mostrarPausa("\n¡Puerto agregado exitosamente!");
                        }
                            
                        break;
                    }
                    case 3: // Eliminar Puerto
                    {
                        System.out.println("Escoja a continuación el Puerto que desea eliminar.");
                        ID idPuerto = dialogar.escogerObjeto(ObjetoRegistrable.Puertos);
                        if( !idPuerto.equals(ID.idNulo) )
                            if( dialogar.pedirDecision("¿Esta seguro que desea eliminar el Puerto (S/N)? " ) )
                                registroPuertos.eliminarPuerto(idPuerto);
                        break;
                    }
                    case 4:
                    {
                        return;
                    }
                }
            } catch (InterruptionException ex) {
                return;
            }
        }
        
    }
   
    /**
     * Método que permite el manejo de navieras con el usuario. Puede ver 
     * registros, agregar navieras o quitar navieras.
     * 
     */
    private void interactuarNavieras()
    {
        while(true)
        {
            limpiarPantalla();
            String mensaje="\nEscoja la opción que desea realizar." +
                    "\n1. Ver las Navieras disponibles." + 
                    "\n2. Ver Barcos de una Naviera." +
                    "\n3. Ingresar una Naviera." + 
                    "\n4. Eliminar una Navieras." + 
                    "\n5. Asignar Naviera a un Barco." + 
                    "\n6. Menu de Barcos." +
                    "\n7. Menú principal.\nOpcion: ";
            try {
                switch(dialogar.pedirInt(mensaje, 1, 7))
                {
                    case 1: // Ver Navieras
                    {
                        //System.out.println("Espere mientras se imprime el registro de navieras");
                        dialogar.mostrarRegistroObjeto(ObjetoRegistrable.Navieras);
                        break;
                    }
                    case 2: // Ver Barcos de Naviera
                    {
                        System.out.println("Escoja la Naviera a ver:");
                        ID idNaviera = dialogar.escogerObjeto(ObjetoRegistrable.Navieras);
                        if( !idNaviera.equals(ID.idNulo) ){
                            Naviera nav = registroNavieras.obtenerNaviera(idNaviera);
                            ID[] barcosNaviera = nav.obtenerBarcos();
                            for (ID idBarco : barcosNaviera) {
                                String nombreBarco = registroBarcos.obtenerNombre(idBarco);
                                if( !nombreBarco.equals("") )
                                    System.out.println("\t" + nombreBarco);
                            }
                        }
                        dialogar.mostrarPausa("");
                        break;
                    }
                    case 3: // Agregar Naviera
                    {
                        ID idNaviera = dialogar.pedirObjeto(ObjetoRegistrable.Navieras);
                        if( !idNaviera.equals(ID.idNulo) ){
                            dialogar.mostrarPausa("\n¡Naviera agregada exitosamente!");
                        }
                        break;
                    }
                    case 4: // Eliminar Naviera
                    {
                        System.out.println("Escoja a continuación la Naviera que desea eliminar.");
                        ID idNaviera = dialogar.escogerObjeto(ObjetoRegistrable.Navieras);
                        if( !idNaviera.equals(ID.idNulo) )
                            if( dialogar.pedirDecision("¿Esta seguro que desea eliminar la Naviera (S/N)? " ) )
                                registroNavieras.eliminarNaviera(idNaviera);
                        break;
                    }    
                    case 5: // Asignar Naviera a un Barco
                    {
                        // Escoger Barco
                        System.out.println("Escoja el Barco que desea cambiar de Naviera");
                        ID idBarco = dialogar.escogerObjeto(ObjetoRegistrable.Barcos);
                        if( idBarco.equals(ID.idNulo) )
                            break;
                        
                        // Escoger Naviera
                        System.out.println("Escoja la Naviera nueva para el Barco");
                        ID idNaviera = dialogar.escogerObjeto(ObjetoRegistrable.Navieras);
                        if( idNaviera.equals(ID.idNulo) )
                            break;
                        
                        // Confirmar
                        if( dialogar.pedirDecision("¿Esta seguro que desea cambiar el Barco de Naviera (S/N)? ")){
                            Naviera nav = registroNavieras.obtenerNaviera(idNaviera);
                            nav.agregarBarco(idBarco);
                        }
                        
                        break;
                    }
                    case 6: // Menu de Barcos
                        interactuarBarcos();
                        break;
                    case 7: // Menu principal
                    {
                        return;
                    }
                }
            } catch (InterruptionException ex) {
                return;
            }
        }
    }
    /**
     * Permite que el usuario consolide una carga en un contenedor para 
     * transportarla via marítima.
     * TODO 
     * 
     */
    private void consolidarCarga()
    {
        while(true)
        {
            limpiarPantalla();
            String mensaje="\nEscoja la opción que desea realizar. "
                    + "\n1. Consolidar Contenedor. "
                    + "\n2. Ubicar contenedor. "
                    + "\n3. Menú principal.\nOpcion: ";
            try{
                switch(dialogar.pedirInt(mensaje, 1, 3))
                {
                    case 1:
                    {
                        ID idCont = dialogar.pedirObjeto(ObjetoRegistrable.Contenedores);
                        if( !idCont.equals(ID.idNulo) ){
                            System.out.println("Contenedor agregado exitosamente.");
                            System.out.println("\tID del Contenedor: " + idCont );
                            System.out.println("NOTA: Guarde el ID del Contenedor "
                                    + "para poder revisar su estado posteriormente.");
                            dialogar.mostrarPausa("");
                        }
                        break;
                    }
                    case 2:
                    {
                        ubicarContenedor();
                        break;
                    }
                    case 3:
                    {
                        return;
                    }    

                }
            }catch(InterruptionException ex){
                return;
            }
        }
    }

    private void ubicarContenedor(){
        try {
            // Pedir ID
            /* Si no lo tiene */
            if (!dialogar.pedirDecision("¿Tiene el ID del Contenedor (S/N)? ")) {
                dialogar.mostrarRegistroObjeto(ObjetoRegistrable.Contenedores);
                return;
            }
            
            String sid = dialogar.pedirString("Ingrese el ID del Contenedor: ");
            ID idCont = ID.parseID(sid);
            Contenedor cont = registroContenedores.obtenerContenedor(idCont);

            // Validar ID
            if (idCont.equals(ID.idNulo) || cont == null) {
                dialogar.mostrarPausa(
                        "**ERROR** : El ID no es un ID válido para Contenedor");
                return;
            }


            // Mostrar eventos del Contenedor
            String nombrePuertoDestino = 
                    registroPuertos.obtenerNombre(cont.obtenerPuertoDestino());
            System.out.print("El Contenedor tiene como destino el Puerto " +
                    nombrePuertoDestino );
            Evento[] eventos = cont.obtenerEventos();
            if (eventos.length == 0) {
                System.out.println(" y no ha salido del Puerto.");
            } else {
                System.out.println(" y ha pasado por los siguientes Puertos: ");
                for (Evento e : eventos) {
                    String nombrePuerto = 
                            registroPuertos.obtenerNombre(e.obtenerPuerto());
                    System.out.println( "\t" + nombrePuerto + " - Fecha: " +
                            e.obtenerFecha() );
                }

                // Buscar el Barco que contiene el Contenedor
                Barco[] barcos = registroBarcos.obtenerTodosBarcos();
                boolean encontrado = false;
                for (Barco barcoActual : barcos) {
                    ID[] idContenedores = barcoActual.obtenerContenedores();
                    for (ID idContenedorActual : idContenedores) {
                        if (idContenedorActual.equals(idCont)) {
                            // ENCONTRADO!
                            Viaje viajeBarco = barcoActual.obtenerViaje();
                            Date tiempoEstimado = viajeBarco.estimarLlegadaPuerto(cont.obtenerPuertoDestino());
                            System.out.println("Fecha estimada de llegada: " + tiempoEstimado);
                            encontrado = true;
                            break;
                        }
                        if (encontrado) {
                            break;
                        }
                    }
                }
            }
            
            dialogar.mostrarPausa("");
        } catch (InterruptionException ex) {
            return;
        }
    }

    /**
    * Realiza la primera interacción con el usuario, siendo este el caso 
    * cuando no se encuentran Puertos o Navieras en los Registros.
    * @param hayNavieras
    * @param hayPuertos
    * @return Regresa true si el usuario desea continuar, y false si decidió
    * salirse del programa
    * @throws Interface.ConsolaUI.InterruptionException 
    */
    private boolean primeraInteraccion(boolean hayNavieras, boolean hayPuertos)
            throws InterruptionException
    {
        System.out.println("\nPara poder continuar se necesita "
                + "tener un registro de: " + 
                (hayNavieras ? "" : "Navieras ") + 
                (hayPuertos ? "" : "Puertos"));
        String mensaje = "Presione\n"
                + "1. Para ingresar Puertos.\n"
                + "2. Para ingresar Navieras.\n"
                + "3. Para salir del programa.\n"
                + "Opcion: ";
        try {
            switch( dialogar.pedirInt(mensaje, 1, 3) )
            {
                case 1:
                {
                    do{
                        ID idPuerto = dialogar.pedirObjeto(ObjetoRegistrable.Puertos);
                        if( idPuerto.equals(ID.idNulo) )
                            break;
                    }while( dialogar.pedirDecision("¿Desea ingresar otro Puerto (S/N)? "));
                    return true;
                }
                case 2:
                {
                    do{
                        ID idNaviera = dialogar.pedirObjeto(ObjetoRegistrable.Navieras);
                        if( idNaviera.equals(ID.idNulo) )
                            break;
                    }while( dialogar.pedirDecision("¿Desea ingresar otra Naviera (S/N)? "));
                    return true;
                }
                case 3:
                    return false;
            }
        } catch (InterruptionException ex) {
            return false;
        }
        return true;
    }

    /**
     * Permite la interacción del Usuario con las Rutas.
     */
    private void interactuarRutas() {
        while( true ){
            limpiarPantalla();
            String mensaje = "\nEscoja la opción que desea realizar." +
                    "\n1. Ver registro de Rutas." +
                    "\n2. Ingresar una nueva Ruta." +
                    "\n3. Regresar al menu anterior.\nOpcion: ";
            
            try{
                switch( dialogar.pedirInt(mensaje, 1, 3) ){
                    case 1: // Ver registro
                    {
                        dialogar.mostrarRegistroObjeto(ObjetoRegistrable.Rutas);
                        break;
                    }
                    case 2: // Ingresar Ruta
                    {
                        ID idRuta = dialogar.pedirObjeto(ObjetoRegistrable.Rutas);
                        if( !idRuta.equals(ID.idNulo) ){
                            dialogar.mostrarPausa("\n¡Ruta ingresada exitosamente!");
                        }
                        break;
                    }
                    case 3: // Regresar
                    {
                        return;
                    }
                }
            }catch( InterruptionException ex ){
                return;
            }
                    
        }
    }
    
    /**
     * Limpia la pantalla de la consola
     */
    private void limpiarPantalla(){
        try{
            String osName = System.getProperty("os.name");
            Process p = null;
            
            if( osName.contains("Linux") )
                p = Runtime.getRuntime().exec("clear");
            else if( osName.contains("Windows") )
                p = Runtime.getRuntime().exec("cls");
            
            if( p == null )
            {
                for (int i = 0; i < 100; i++) {
                    System.out.println("\n");
                }
            }
            else{
                BufferedReader input = new BufferedReader(
                        new InputStreamReader(p.getInputStream()));
                String linea = "";
                while( (linea = input.readLine()) != null )
                    System.out.println(linea);
                input.close();
            }
        }catch( Exception ex ){
            return;
        }
    }
}
